package geppetto.reordering;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

import gnu.trove.TIntDoubleHashMap;
import gnu.trove.TIntObjectHashMap;

public class ReorderingInfo {
	
//	protected TIntdoubleHashMap previousWordOrientationCounts = new TIntdoubleHashMap();
//	protected TIntdoubleHashMap nextWordOrientationCounts = new TIntdoubleHashMap();
	
	protected double[][] previousWordOrientations = new double[3][];
	protected double[][] nextWordOrientations = new double[3][];
	
	public ReorderingInfo() {
		super();
		for(int i = 0; i < previousWordOrientations.length; i++){
			previousWordOrientations[i] = new double[0];
			nextWordOrientations[i] = new double[0];
		}
	}
	
	public ReorderingInfo(int previousWordOrientation,
			int nextWordOrientation) {
		this();
		addPrevWordOrientation(previousWordOrientation);
		addNextWordOrientation(nextWordOrientation);
	}
	
	public void addPrevWordOrientation(int orientation){
		addPrevWordOrientation(orientation, 1);
	}
	
	public void addNextWordOrientation(int orientation){
		addNextWordOrientation(orientation, 1);
	}
	
	public void addPrevWordOrientation(int orientation, double count){
		//System.out.println("orientation -> " + orientation + ":" + count);
/*		if (!previousWordOrientations.contains(orientation)){
			previousWordOrientations.put(orientation, new ArrayList<double>());
		}
		previousWordOrientations.get(orientation).add(count);*/
		double[] oldArray = previousWordOrientations[orientation-1];
		double[] newArray = Arrays.copyOf(oldArray, oldArray.length+1);
		newArray[oldArray.length] = count;
		previousWordOrientations[orientation-1] = newArray;
		/*if (!previousWordOrientationCounts.contains(orientation)){
			previousWordOrientationCounts.put(orientation, count);
		}
		else{
			previousWordOrientationCounts.put(orientation, previousWordOrientationCounts.get(orientation) + count);
		}*/
	}
	
	public void addNextWordOrientation(int orientation, double count){
		/*if (!nextWordOrientations.contains(orientation)){
			nextWordOrientations.put(orientation, new ArrayList<double>());
		}
		nextWordOrientations.get(orientation).add(count);*/
		double[] oldArray = nextWordOrientations[orientation-1];
		double[] newArray = Arrays.copyOf(oldArray, oldArray.length + 1);
		newArray[oldArray.length] = count;
		nextWordOrientations[orientation-1] = newArray;
			/*if (!nextWordOrientationCounts.contains(orientation)){
			nextWordOrientationCounts.put(orientation, count);
		}
		else{
			nextWordOrientationCounts.put(orientation, nextWordOrientationCounts.get(orientation) + count);
		}*/
	}

	public TIntDoubleHashMap getPreviousWordOrientationCounts() {
		TIntDoubleHashMap ret = new TIntDoubleHashMap();
		for(int i = 0; i<previousWordOrientations.length; i++){
			double acc = 0;
			for(double count : previousWordOrientations[i]){
				acc+=count;
			}
			ret.put(i+1, acc);
		}
		return ret;
	}

	public TIntDoubleHashMap getNextWordOrientationCounts() {
		TIntDoubleHashMap ret = new TIntDoubleHashMap();
		for(int i = 0; i<nextWordOrientations.length; i++){
			double acc = 0;
			for(double count : nextWordOrientations[i]){
				acc+=count;
			}
			ret.put(i+1, acc);
		}
		return ret;
	}	
	
	public void merge(ReorderingInfo info){
		for(int i = 0; i < getPreviousWordOrientations().length; i++){
			for(double count : info.getPreviousWordOrientations()[i]){
				addPrevWordOrientation(i+1, count);
			}
//			addPrevWordOrientation(key, info.getPreviousWordOrientationCounts().get(key));
		}
		for(int i = 0; i < getNextWordOrientations().length; i++){
			for(double count : info.getNextWordOrientations()[i]){
				addNextWordOrientation(i+1, count);
			}
//			addNextWordOrientation(key, info.getNextWordOrientationCounts().get(key));
		}
	}
	
	// combines all entries into one
	public static void compact(ReorderingInfo info){
		normalize(info);
		TIntDoubleHashMap prevReordCounts = new TIntDoubleHashMap();
		TIntDoubleHashMap nextReordCounts = new TIntDoubleHashMap();
		for(int key : prevReordCounts.keys()){
			double[] value = new double[1];
			value[0]=prevReordCounts.get(key);
			info.getPreviousWordOrientations()[key-1]=value;
		}
		for(int key : nextReordCounts.keys()){
			double[] value = new double[1];
			value[0]=nextReordCounts.get(key);
			info.getNextWordOrientations()[key-1]=value;
		}
	}
	
	public static void normalize(ReorderingInfo info){
		double length = 0;
		double prevMax = 0;
		double nextMax = 0;
		for(int i = 0; i < info.getPreviousWordOrientations().length; i++){
			length = info.getPreviousWordOrientations()[i].length;
		}
		
		for(int i = 0; i < length; i++){
			double total = 0;
			for(int j = 0; j < info.getPreviousWordOrientations().length; j++){
				total += info.getPreviousWordOrientations()[j][i];
			}
			prevMax = Math.max(prevMax, total);
		}
		for(int i = 0; i < length; i++){
			double total = 0;
			for(int j = 0; j < info.getPreviousWordOrientations().length; j++){
				total += info.getPreviousWordOrientations()[j][i];
			}
			double ratio = total / prevMax;
			for(int j = 0; j < info.getPreviousWordOrientations().length; j++){
				double count = info.getPreviousWordOrientations()[j][i];
				double normalizedCount = count * ratio / total;
				info.getPreviousWordOrientations()[j][i]=normalizedCount;
			}
		}
		
		for(int i = 0; i < length; i++){
			double total = 0;
			for(int j = 0; j < info.getNextWordOrientations().length; j++){
				total += info.getNextWordOrientations()[j][i];
			}
			nextMax = Math.max(nextMax, total);
		}
		for(int i = 0; i < length; i++){
			double total = 0;
			for(int j = 0; j < info.getNextWordOrientations().length; j++){
				total += info.getNextWordOrientations()[j][i];
			}
			double ratio = total / nextMax;
			for(int j = 0; j < info.getNextWordOrientations().length; j++){
				double count = info.getNextWordOrientations()[j][i];
				double normalizedCount = count * ratio / total;
				info.getNextWordOrientations()[j][i]=normalizedCount;
			}
		}
	}
	
	public static double getTotalCount(ReorderingInfo info){
		double res = 0;
		for(double count : info.getPreviousWordOrientationCounts().getValues()){
			res+=count;
		}
		return res;
	}

	public double[][] getPreviousWordOrientations() {
		return previousWordOrientations;
	}

	public double[][] getNextWordOrientations() {
		return nextWordOrientations;
	}

	
}
